package net.aiion.weave.impl.resources.url;

import java.io.File;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URL;

import net.aiion.weave.spi.resources.ResourceException;
import net.aiion.weave.spi.resources.url.URLConverter;

public class JBossAS71URLConverter implements URLConverter
{
    private static final String EXTENSION_JAR = ".jar";
    private static final String EXTENSION_WAR = ".war";

    private static final int EXTENSION_JAR_LENGTH = 4;
    private static final int EXTENSION_WAR_LENGTH = 4;

    private static final String METHOD_NAME_GET_PHYSICAL_FILE = "getPhysicalFile";

    private Method getPhysicalFileMethod;

    public JBossAS71URLConverter() {
    }

    @Override
    public URL convertURL(final URL aURL) {
        try {
            return convertURL1(aURL);
        } catch (final MalformedURLException e) {
            throw new ResourceException(e);
        }
    }

    private URL convertURL1(final URL aURL) throws MalformedURLException {
        if (!aURL.getProtocol().startsWith("vfs")) {
            return aURL;
        }

        final String urlString = aURL.toString();
        if (urlString.contains(EXTENSION_JAR)) {
            final int warPartEnd = urlString.indexOf(EXTENSION_WAR) + EXTENSION_JAR_LENGTH;
            final int jarPartEnd = urlString.indexOf(EXTENSION_JAR) + EXTENSION_WAR_LENGTH;
            final String warPart = urlString.substring(0, warPartEnd);
            final String jarPart = urlString.substring(warPartEnd, jarPartEnd);
            final String packagePart = urlString.substring(jarPartEnd);

            final String physicalWarDirString = getPhysicalFileURI(new URL(warPart)).toString();
            return new URL(String.format("jar:%s%s!%s", physicalWarDirString, jarPart, packagePart));
        }

        return getPhysicalFileURI(aURL).toURL();
    }

    private URI getPhysicalFileURI(final URL aJBossVFSURL) {
        try {
            final Object jBossVirtualFile = aJBossVFSURL.openConnection().getContent();
            return getPhysicalFile(jBossVirtualFile).toURI();
        } catch (final IOException e) {
            throw new ResourceException(e);
        }
    }

    private File getPhysicalFile(final Object aJBossVirtualFile) {
        try {
            return (File) getGetPhysicalFileMethod(aJBossVirtualFile).invoke(aJBossVirtualFile);
        } catch (final IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
            throw new ResourceException(e);
        }
    }

    private Method getGetPhysicalFileMethod(final Object aJBossVirtualFile) {
        if (getPhysicalFileMethod != null) {
            return getPhysicalFileMethod;
        }

        final Class<?> jbossVirtualFileClass = aJBossVirtualFile.getClass();
        try {
            getPhysicalFileMethod = jbossVirtualFileClass.getMethod(METHOD_NAME_GET_PHYSICAL_FILE);
            return getPhysicalFileMethod;
        } catch (final NoSuchMethodException e) {
            try {
                getPhysicalFileMethod = jbossVirtualFileClass.getDeclaredMethod(METHOD_NAME_GET_PHYSICAL_FILE);
            } catch (final NoSuchMethodException | SecurityException e1) {
                throw new ResourceException(e1);
            }
            getPhysicalFileMethod.setAccessible(true);
            return getPhysicalFileMethod;
        }
    }
}
